package com.alkalinesolutions.json.compat;

import java.io.Serializable;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Iterator;

import org.json.JSONArray;
import org.json.JSONObject;

import com.alkalinesolutions.json.core.DuplicateKeyException;
import com.alkalinesolutions.json.core.impl.JSONEvent;

/** Emit a JSONArray or JSONObject based on a stream of JSONEvents.
 *
 *
 * @author David Waite &lt;<a href='mailto:david@alkaline-solutions.com'>david@alkaline-solutions.com</a>&gt;
 */
public class OrgJsonEmitter {
	public Object parse(Iterable<JSONEvent> events)
		throws com.alkalinesolutions.json.core.JSONException {
		try {
			Iterator<JSONEvent> it = events.iterator();
			while (it.hasNext()) {
				JSONEvent event = it.next();
				switch (event.getType()) {
					case StartArray:
						JSONArray array = new JSONArray();
						parse(array, it);
						return array;
					case StartObject:
						JSONObject object = new JSONObject();
						parse(object, it);
						return object;
					default:
						throw new com.alkalinesolutions.json.core.JSONException();
				}
			}
		throw new com.alkalinesolutions.json.core.JSONException(Messages.getString("OrgJsonEmitter.0")); //$NON-NLS-1$
		}
		catch (UndeclaredThrowableException e) {
			if (e.getCause() instanceof com.alkalinesolutions.json.core.JSONException) {
				throw  (com.alkalinesolutions.json.core.JSONException)e.getCause();
			}
			throw new com.alkalinesolutions.json.core.JSONException(e.getCause());
		}

	}
	
	private void parse(JSONObject parent, Iterator<JSONEvent> it)
		throws com.alkalinesolutions.json.core.JSONException {
		while (it.hasNext()) {
			JSONEvent event = it.next();
			Object data = event.getData();
			String key = event.getKey();
			
			if (parent.has(key))
				throw new DuplicateKeyException(key);
			if (data == null)
				data = JSONObject.NULL;
			try {
				switch (event.getType()) {
				case Boolean:
				case Null:
				case Number:
				case String:
					parent.put(key, data);
					break;
				case StartArray:
					JSONArray array = new JSONArray();
					parse(array, it);
					parent.put(key, array);
					break;
				case StartObject:
					JSONObject object = new JSONObject();
					parse(object, it);
					parent.put(key, object);
					break;
				case EndArray:
				case EndObject:
					return;
				}
			}
			catch (org.json.JSONException e) {
				throw new com.alkalinesolutions.json.core.JSONException(e.getMessage());
			}
		}
		throw new com.alkalinesolutions.json.core.JSONException(Messages.getString("OrgJsonEmitter.0")); //$NON-NLS-1$
	}
		
	private void parse(JSONArray parent, Iterator<JSONEvent> it)
		throws com.alkalinesolutions.json.core.JSONException {
		while (it.hasNext()) {
			JSONEvent event = it.next();
			Serializable data = event.getData();
			switch (event.getType()) {
			case Boolean:
			case Null:
			case Number:
			case String:
				parent.put(data);
				break;
			case StartArray:
				JSONArray array = new JSONArray();
				parse(array, it);
				parent.put(array);
				break;
			case StartObject:
				JSONObject object = new JSONObject();
				parse(object, it);
				parent.put(object);
				break;
			case EndArray:
			case EndObject:
				return;
			}
		}
		throw new com.alkalinesolutions.json.core.JSONException(Messages.getString("OrgJsonEmitter.0")); //$NON-NLS-1$
	}
}